package com.zenika.zenbinding.client.handler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.zenika.zenbinding.client.model.ListModel;
import com.zenika.zenbinding.client.model.NullValueModel;
import com.zenika.zenbinding.client.model.ValueModel;

/**
 * Abstract class extended by an handler bounds with a ListModel. It implements
 * the Observer pattern to notify the ListModel in case of change in the
 * elements selection.
 * @author Zenika
 */
public abstract class ListBindingHandler implements Handler {

	private List listenerList;
	protected HashMap valueMap;

	public ListBindingHandler() {
		this.listenerList = new ArrayList();
		this.valueMap = new HashMap();
	}

	protected void setChoices(List valueList) {
		Iterator iter = valueList.iterator();
		while (iter.hasNext()) {
			ValueModel model = (ValueModel) iter.next();
			String value = model.getValue();
			this.valueMap.put(value, model.getObject());
			this.addItem(value);
		}
	}

	public void fireChange(List selectedItems) {
		Iterator iter = this.listenerList.iterator();
		while (iter.hasNext()) {
			((ListBindingListener) iter.next()).onChange(selectedItems, this);
		}
	}

	public void addListBindingListener(ListBindingListener listener) {
		this.listenerList.add(listener);
	}

	public void removeListBindingListener(ListBindingListener listener) {
		this.listenerList.remove(listener);
	}

	public abstract void setErrorStyle();

	public abstract void setRegularStyle();

	public void setListModel(ListModel model) {
		model.setHandler(this);
		this.addListBindingListener(model);
		this.setSelectedItems(model.getList(this));
	}

	/**
	 * Add an item in the selection of the handled widget.
	 * @param item String displayed
	 */
	public abstract void addItem(String item);

	/**
	 * Get the object represented by the String item.
	 * @param item
	 * @return
	 */
	public Object getObject(String item) {
		return this.valueMap.get(item);
	}

	public abstract void setItemSelected(String item, boolean selected);

	/**
	 * Set the items which have to be shown as selected.
	 * @param selectedItems List of selected items.
	 */
	private void setSelectedItems(List selectedItems) {
		Iterator iter = selectedItems.iterator();
		while (iter.hasNext()) {
			Object selectedObject = iter.next();

			Set keys = this.valueMap.keySet();
			Iterator iter2 = keys.iterator();
			while (iter2.hasNext()) {
				String item = iter2.next().toString();

				// if this is a fake entry that acts as blank
				boolean isBlank = NullValueModel.VALUE.equals(item);

				if ((isBlank && (selectedObject == null))
						|| ((this.valueMap.get(item) != null) && this.valueMap.get(item).equals(selectedObject))) {
					this.setItemSelected(item, true);
				}
			}
		}
	}

}
